#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>

#define NUM 100
#define BOARD_SIZE 16  // 棋盘大小

// 棋盘数据结构
typedef int Board[BOARD_SIZE][BOARD_SIZE];

// 全局变量：保存当前游戏棋盘状态
int global_board[BOARD_SIZE][BOARD_SIZE] = {0};
int game_active = 0; // 标记是否有游戏正在进行

int main()
{
    // 添加重玩请求相关变量
    int restart_requested = 0;  // 标记是否有重玩请求
    int requesting_client = -1; // 请求重玩的客户端
    
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket");
        return -1;
    }

    // 设置端口复用
    int opt = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(6969);  // 使用6969端口
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    int ret = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
    if (ret < 0)
    {
        perror("bind");
        return -1;
    }

    ret = listen(sockfd, 5);
    if (ret < 0)
    {
        perror("listen");
        return -1;
    }

    fd_set readfds;
    int cfds[NUM] = {0};  // 客户端套接字数组
    int maxfd = sockfd;
    printf("服务器启动，等待连接...\n");

    while (1)
    {
        FD_ZERO(&readfds);
        FD_SET(sockfd, &readfds);
        
        // 将活跃的客户端套接字加入监听集合
        for (int i = 0; i < NUM; i++)
        {
            if (cfds[i] != 0)
            {
                FD_SET(cfds[i], &readfds);
                maxfd = maxfd > cfds[i] ? maxfd : cfds[i];
            }
        }

        // 等待IO事件
        ret = select(maxfd + 1, &readfds, NULL, NULL, NULL);
        if (ret < 0)
        {
            perror("select");
            continue;
        }

        // 处理新连接
        if (FD_ISSET(sockfd, &readfds))
        {
            struct sockaddr_in client_addr;
            socklen_t len = sizeof(client_addr);
            int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &len);
            if (clientfd < 0)
            {
                perror("accept");
                continue;
            }
            
            // 保存客户端套接字
            for (int i = 0; i < NUM; i++)
            {
                if (cfds[i] == 0)
                {
                    cfds[i] = clientfd;
                    printf("客户端 %s:%d 已连接\n", 
                           inet_ntoa(client_addr.sin_addr),
                           ntohs(client_addr.sin_port));
                    
                    // 计算已连接的客户端数量
                    int client_count = 0;
                    for (int j = 0; j < NUM; j++) {
                        if (cfds[j] != 0) {
                            client_count++;
                        }
                    }
                    
                    // 发送客户端编号（1或2）
                    int client_id = (client_count > 2) ? 0 : client_count;
                    send(clientfd, &client_id, sizeof(client_id), 0);
                    
                    // 如果这是第二个客户端，通知第一个客户端游戏开始
                    if (client_id == 2) {
                        int game_start_signal = 10; // 游戏开始信号
                        for (int j = 0; j < NUM; j++) {
                            if (cfds[j] != 0 && j != i) {
                                send(cfds[j], &game_start_signal, sizeof(game_start_signal), 0);
                                printf("已通知客户端 %d 游戏开始\n", cfds[j]);
                            }
                        }
                    }
                    
                    // 重置重玩相关状态，避免重连时发送旧的胜利标志
                    restart_requested = 0;
                    requesting_client = -1;
                    
                    // 清除可能存在的旧信号缓冲区
                    char buffer[1024];
                    int clear_ret;
                    do {
                        clear_ret = recv(clientfd, buffer, sizeof(buffer), MSG_DONTWAIT);
                    } while (clear_ret > 0);
                    printf("已清除客户端 %d 的旧信号缓冲区\n", clientfd);
                    
                    // 如果有活跃的游戏进行中，向新连接的客户端发送当前棋盘状态
                    if (game_active) {
                        printf("向客户端 %d 发送当前棋局状态\n", clientfd);
                        // 将二维数组转换为一维数组发送
                        int flat_board[BOARD_SIZE * BOARD_SIZE];
                        for (int row = 0; row < BOARD_SIZE; row++) {
                            for (int col = 0; col < BOARD_SIZE; col++) {
                                flat_board[row * BOARD_SIZE + col] = global_board[row][col];
                            }
                        }
                        send(clientfd, flat_board, sizeof(flat_board), 0);
                    }
                    
                    break;
                }
            }
        }

        // 处理客户端数据
        for (int i = 0; i < NUM; i++)
        {
            if (cfds[i] != 0 && FD_ISSET(cfds[i], &readfds))
            {
                // 尝试先读取是否是特殊信号
                int signal = 0;
                ret = recv(cfds[i], &signal, sizeof(signal), MSG_PEEK);
                
                // 优先处理重连信号，避免处理旧的胜利标志
                if (ret > 0 && signal == 11) {
                    ret = read(cfds[i], &signal, sizeof(signal));
                    printf("客户端 %d 发送重连信号，清除所有旧状态\n", cfds[i]);
                    
                    // 清除所有旧状态
                    restart_requested = 0;
                    requesting_client = -1;
                    
                    // 通知其他客户端有玩家重连
                    int reconnect_notify = 12; // 重连通知信号
                    for (int j = 0; j < NUM; j++) {
                        if (j != i && cfds[j] != 0) {
                            send(cfds[j], &reconnect_notify, sizeof(reconnect_notify), 0);
                            printf("已通知客户端 %d 有玩家重连\n", cfds[j]);
                        }
                    }
                    continue;
                }
                // 处理回合状态信号
                else if (ret > 0 && signal == 13) {
                    ret = read(cfds[i], &signal, sizeof(signal));
                    printf("客户端 %d 发送回合状态信号\n", cfds[i]);
                    
                    // 读取回合状态
                    int turn_state = 0;
                    ret = read(cfds[i], &turn_state, sizeof(turn_state));
                    if (ret > 0) {
                        printf("客户端 %d 的回合状态: %d\n", cfds[i], turn_state);
                        
                        // 转发回合状态给其他客户端
                        for (int j = 0; j < NUM; j++) {
                            if (j != i && cfds[j] != 0) {
                                // 发送回合状态信号
                                int turn_signal = 13;
                                send(cfds[j], &turn_signal, sizeof(turn_signal), 0);
                                // 发送回合状态（对方收到时应该取反）
                                int opposite_turn = (turn_state == 1) ? 0 : 1;
                                send(cfds[j], &opposite_turn, sizeof(opposite_turn), 0);
                                printf("已转发回合状态给客户端 %d，对方回合:%d\n", cfds[j], opposite_turn);
                            }
                        }
                    }
                    continue;
                }
                // 然后处理胜利标志（1表示黑胜，2表示白胜）
                else if (ret > 0 && (signal == 1 || signal == 2)) {
                    // 确认是胜利标志
                    ret = read(cfds[i], &signal, sizeof(signal));
                    
                    // 输出胜利信息
                    if (signal == 1) {
                        printf("接收到黑胜标志，客户端 %d\n", cfds[i]);
                    } else {
                        printf("接收到白胜标志，客户端 %d\n", cfds[i]);
                    }
                    
                    // 转发胜利标志给另一个客户端
                    for (int j = 0; j < NUM; j++) {
                        if (j != i && cfds[j] != 0) {
                            // 直接转发接收到的胜利标志
                            ret = send(cfds[j], &signal, sizeof(signal), 0);
                            if (ret < 0) {
                                perror("send win flag");
                            }
                            printf("已转发胜利标志 %d 给客户端 %d\n", signal, cfds[j]);
                            break;
                        }
                    }
                    
                    // 不立即断开客户端连接，让客户端可以显示胜利画面和处理返回/重开
                    // 客户端将在用户点击返回或重开后自行断开连接
                    continue;
                }
                // 然后处理其他特殊信号（使用不同的值避免冲突）
                else if (ret > 0 && signal == 8) {  // 重玩请求使用8而不是1，避免与黑胜标志冲突
                    ret = read(cfds[i], &signal, sizeof(signal));
                    printf("客户端 %d 请求重玩（当前状态：%s）\n",
                           cfds[i], restart_requested ? "已有请求" : "首次请求");

                    if (restart_requested) {
                        // 双方都请求重玩，广播同步重置信号
                        restart_requested = 0;
                        requesting_client = -1;
                        int restart_notify = 3;  // 通知双方同步重玩
                        for (int j = 0; j < NUM; j++) {
                            if (cfds[j] != 0) {
                                send(cfds[j], &restart_notify, sizeof(restart_notify), 0);
                            }
                        }
                    } else {
                        // 第一个请求，通知对方
                        restart_requested = 1;
                        requesting_client = cfds[i];
                        int restart_request = 4;  // 通知另一方有重玩请求
                        for (int j = 0; j < NUM; j++) {
                            if (j != i && cfds[j] != 0) {
                                send(cfds[j], &restart_request, sizeof(restart_request), 0);
                            }
                        }
                    }
                    continue;
                }
                else if (ret > 0 && signal == 5) { // 同意重玩响应
                    ret = read(cfds[i], &signal, sizeof(signal));
                    
                    if (restart_requested) {
                        // 另一个客户端同意重玩
                        restart_requested = 0;
                        
                        // 向所有客户端广播重新开始信号
                        int restart_notify = 3;
                        for (int j = 0; j < NUM; j++) {
                            if (cfds[j] != 0) {
                                ret = send(cfds[j], &restart_notify, sizeof(restart_notify), 0);
                                if (ret < 0) {
                                    perror("send");
                                    close(cfds[j]);
                                    cfds[j] = 0;
                                }
                            }
                        }
                    }
                    continue;
                }
                else if (ret > 0 && signal == 6) { // 拒绝重玩响应
                    ret = read(cfds[i], &signal, sizeof(signal));
                    
                    if (restart_requested) {
                        // 另一个客户端拒绝重玩
                        restart_requested = 0;
                        
                        // 通知请求方重玩被拒绝
                        int restart_denied = 7; // 重玩被拒绝信号
                        if (requesting_client != -1) {
                            ret = send(requesting_client, &restart_denied, sizeof(restart_denied), 0);
                            if (ret < 0) {
                                perror("send");
                            }
                        }
                        requesting_client = -1;
                    }
                    continue;
                }
                
                // 如果不是特殊信号，则继续处理棋盘数据
                int board_data[16*16] = {0};  // 使用一维数组接收数据
                size_t expected_size = sizeof(board_data);
                // 读取棋盘数据
                ret = read(cfds[i], board_data, expected_size);
                if (ret <= 0)
                {
                    printf("客户端 %d 离线\n", cfds[i]);
                    
                    // 通知其他客户端有玩家离线
                    int disconnect_signal = 9; // 使用9表示断线信号
                    int remaining_clients = 0;
                    for (int j = 0; j < NUM; j++) {
                        if (j != i && cfds[j] != 0) {
                            send(cfds[j], &disconnect_signal, sizeof(disconnect_signal), 0);
                            printf("已通知客户端 %d 有玩家离线\n", cfds[j]);
                            remaining_clients++;
                        }
                    }
                    
                    close(cfds[i]);
                    cfds[i] = 0;
                    
                    // 只有当所有客户端都断开连接时，才重置游戏状态
                    if (remaining_clients == 0) {
                        restart_requested = 0;
                        requesting_client = -1;
                        printf("所有客户端已断开，重置游戏状态，准备新棋局\n");
                        // 重置全局棋盘和游戏活跃标志
                        memset(global_board, 0, sizeof(global_board));
                        game_active = 0;
                    } else {
                        printf("客户端 %d 已断开，但仍有其他客户端在线，保留当前棋局状态\n", cfds[i]);
                    }
                    
                    continue;
                }
                
                // 打印服务器收到文件的大小
                printf("服务器收到: 客户端%d发送的文件大小=%d字节，期望大小=%zu字节\n", 
                       cfds[i], ret, expected_size);
                
                // 打印服务器收到棋子的坐标
                 printf("服务器收到棋子坐标:\n");
                 int has_piece = 0;
                 for (int idx = 0; idx < 16*16; idx++) {
                     int row = idx / 16;
                     int col = idx % 16;
                     if (board_data[idx] != 0) {
                         printf("  位置[行=%d][列=%d]，棋子颜色=%d\n", row, col, board_data[idx]);
                         has_piece = 1;
                         // 更新全局棋盘状态
                         global_board[row][col] = board_data[idx];
                     } else {
                         // 确保空位置也被正确更新
                         global_board[row][col] = 0;
                     }
                 }
                if (!has_piece) {
                    printf("  未发现有效棋子\n");
                }
                
                // 标记游戏为活跃状态
                game_active = 1;

                // 转发给其他客户端
                for (int j = 0; j < NUM; j++)
                {
                    if (j != i && cfds[j] != 0)
                    {
                        size_t send_size = sizeof(board_data);
                        ret = send(cfds[j], board_data, send_size, 0);
                        if (ret < 0)
                        {
                            perror("send");
                            close(cfds[j]);
                            cfds[j] = 0;
                        } else {
                            // 打印服务器转发棋子的坐标和文件大小
                            printf("服务器转发: 转发给客户端%d，文件大小=%d字节\n", cfds[j], ret);
                            printf("服务器转发棋子坐标:\n");
                            for (int idx = 0; idx < 16*16; idx++) {
                                 int row = idx / 16;
                                 int col = idx % 16;
                                 if (board_data[idx] != 0) {
                                     printf("  转发位置[行=%d][列=%d]，棋子颜色=%d\n", row, col, board_data[idx]);
                                 }
                             }
                        }
                    }
                }
            }
        }
    }
    
    close(sockfd);
    return 0;
}